package com.joolun.weixin.handler.tp;

import com.alibaba.fastjson2.JSON;
import com.joolun.common.constant.Constants;
import com.joolun.common.utils.spring.SpringUtils;
import com.joolun.common.utils.uuid.IdUtils;
import com.joolun.system.domain.ScrmCustomerInfo;
import com.joolun.system.domain.ScrmCustomerStaff;
import com.joolun.system.domain.SysCorpConfig;
import com.joolun.system.service.impl.SysCorpConfigServiceImpl;
import com.joolun.weixin.builder.cp.TextBuilder;
import com.joolun.weixin.config.WxCpConfiguration;
import com.joolun.weixin.entity.dto.WxCpXmlOutMessageDTO;
import com.joolun.weixin.handler.CpAbstractHandler;
import com.joolun.weixin.handler.customer.AbstractUpdateCustomerHandler;
import com.joolun.weixin.service.IBrCustomerDynamicService;
import com.joolun.weixin.service.IScrmCustomerInfoService;
import com.joolun.weixin.service.IScrmCustomerStaffService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.cp.api.WxCpExternalContactService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.impl.WxCpExternalContactServiceImpl;
import me.chanjar.weixin.cp.bean.external.contact.FollowedUser;
import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactBatchInfo;
import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo;
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
import me.chanjar.weixin.cp.constant.WxCpConsts;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 获客链接事件
 *
 * @author xuxh
 * @date 2022/2/15 10:53
 */

@Slf4j
@Service(WxCpConsts.EventType.CUSTOMER_ACQUISITION)
@Transactional
public class WxChangeExternalCustomerHandler extends CpAbstractHandler {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private IScrmCustomerInfoService customerService;

    @Autowired
    private IScrmCustomerStaffService customerStaffService;

    private static List<AbstractUpdateCustomerHandler> updateCustomerHandlerList;

    @Autowired
    private IBrCustomerDynamicService customerDynamicService;

    @Autowired
    private SysCorpConfigServiceImpl sysCorpConfigService;


    @Override
    public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, Map<String, Object> map, WxCpService wxCpService, WxSessionManager wxSessionManager) throws WxErrorException {

        WxCpXmlOutMessageDTO dto = new WxCpXmlOutMessageDTO();
        BeanUtils.copyProperties(wxMessage, dto);
        System.out.println("wxCpService.getWxCpConfigStorage().getCorpId() -------------------- " + wxCpService.getWxCpConfigStorage().getCorpId());
        dto.setExtCorpId(wxCpService.getWxCpConfigStorage().getCorpId());

        log.debug("客户相关mq发送：[{}], [{}]", wxMessage.getChangeType(), JSON.toJSONString(dto));
        rabbitTemplate.convertAndSend(wxMessage.getChangeType(), dto);
        try {
            String content = "感谢反馈，您的信息已收到！";
            return new TextBuilder().build(content, wxMessage, null);
        } catch (Exception e) {
            log.error("获客链接事件消息接收异常", e);
            return null;
        }
    }


    /**
     * 监听事件: 获客链接异常事件
     *
     * @param dto 消息
     * @author xuxh
     * @date 2022/2/16 10:29
     */
    @RabbitListener(queues = WxCpConsts.CustomerAcquisitionChangeType.LINK_UNAVAILABLE)
    public void customerDeleteStaff(WxCpXmlOutMessageDTO dto) {
        String str = IdUtils.get32UUID();
        log.info("消费MQ:[link_unavailable],事件描述:[获客链接异常事件],编号:[{}],企业ID:[{}],message[{}]", str, dto.getExtCorpId(), dto);
        try {
            // TODO:获客链接异常，这里需要停止当前接量。可及时调整链接配置或流量曝光策略，避免流量浪费
//            WxStaffDeleteCustomerDTO customerDTO = new WxStaffDeleteCustomerDTO()
//                    .setExtCorpId(dto.getExtCorpId())
//                    .setCustomerExtId(dto.getExternalUserId())
//                    .setDeleteTime(dto.getCreateTime() == null ? new Date() : new Date(dto.getCreateTime() * 1000))
//                    .setType(1)
//                    .setStaffExtId(dto.getUserId());
//            customerService.staffDeleteCustomer(customerDTO);

            //应用宝和渠道活码的处理
            //otherDeleteHandle(dto);
            //客户动态
            customerDynamicService.saveByQueue(WxCpConsts.CustomerAcquisitionChangeType.LINK_UNAVAILABLE, dto.getExtCorpId(), dto.getUserId(), dto.getExternalUserId(), null);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("消费MQ异常:[link_unavailable],事件描述:[获客链接异常事件],编号:[{}],企业ID:[{}],message[{}],异常原因:[{}],异常描述:[{}]", str, dto.getExtCorpId(), dto, "系统异常", e);
        }
    }


    /**
     * 监听事件: 微信客户打开获客链接事件-当微信客户通过获客链接进入成员的profile页时，回调此事件
     *
     * @param dto 消息
     * @author xuxh
     * @date 2022/2/16 10:29
     */
    @RabbitListener(queues = Constants.WX_OPEN_PROFILE)
    public void staffDeleteCustomer(WxCpXmlOutMessageDTO dto) {
        String str = IdUtils.get32UUID();
        log.info("消费MQ:[open_profile],事件描述:[微信客户打开获客链接事件],编号:[{}],企业ID:[{}],message[{}]", str, dto.getExtCorpId(), dto);
        try {
//            WxStaffDeleteCustomerDTO customerDTO = new WxStaffDeleteCustomerDTO()
//                    .setDeleteByTransfer(Objects.equals("DELETE_BY_TRANSFER",dto.getSource()))
//                    .setExtCorpId(dto.getExtCorpId())
//                    .setCustomerExtId(dto.getExternalUserId())
//                    .setDeleteTime(dto.getCreateTime() == null ? new Date() : new Date(dto.getCreateTime() * 1000))
//                    .setType(2)
//                    .setStaffExtId(dto.getUserId());
//            customerService.staffDeleteCustomer(customerDTO);

            //应用宝和渠道活码的处理
            otherDeleteHandle(dto);
            //客户动态
            customerDynamicService.saveByQueue(Constants.WX_OPEN_PROFILE, dto.getExtCorpId(), dto.getUserId(), dto.getExternalUserId(), null);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("消费MQ异常:[open_profile],事件描述:[微信客户打开获客链接事件],编号:[{}],企业ID:[{}],message[{}],异常原因:[{}],异常描述:[{}]", str, dto.getExtCorpId(), dto, "系统异常", e);
        }
    }

    private void otherDeleteHandle(WxCpXmlOutMessageDTO dto) {
        for (AbstractUpdateCustomerHandler handler : getUpdateCustomerHandlerList()) {

            if (handler.match(dto.getExtCorpId(), dto.getUserId(), dto.getState())) {
                log.info("客户删除事件，匹配到handle：" + handler);
                handler.deleteHandle(dto);
            }

        }
    }

    /**
     * 监听事件: 通过获客链接发起好友请求事件
     *
     * @param dto 消息
     * @author xuxh
     * @date 2022/2/16 10:29
     */
    @RabbitListener(queues = WxCpConsts.CustomerAcquisitionChangeType.friend_request)
    public void addHalfExternalContact(WxCpXmlOutMessageDTO dto) {
        String str = IdUtils.get32UUID();
        log.info("消费MQ:[friend_request],事件描述:[通过获客链接发起好友请求事件],编号:[{}],企业ID:[{}],message[{}]", str, dto.getExtCorpId(), dto);

        RLock lock = customerService.getCustomerSyncLock(dto.getExtCorpId(), dto.getExternalUserId());
        try {
            if (customerService.trySyncLock(lock)) {
//                refreshCustomer(dto);
//                //渠道活码和应用宝
////                WxCpConfiguration.getExtCorpIdThread().set(dto.getExtCorpId());
//                otherAddHandler(dto);
//                //客户动态
                customerDynamicService.saveByQueue(WxCpConsts.CustomerAcquisitionChangeType.friend_request, dto.getExtCorpId(), dto.getUserId(), dto.getExternalUserId(), null);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("消费MQ异常:[friend_request],事件描述:[通过获客链接发起好友请求事件],编号:[{}],企业ID:[{}],message[{}],异常原因:[{}],异常描述:[{}]", str, dto.getExtCorpId(), dto, "系统异常", e);
        } finally {
            customerService.releaseSyncLock(lock);
        }

    }

    /**
     * 监听事件: 成员首次收消息事件
     *
     * @param dto 消息
     * @author xuxh
     * @date 2022/2/16 10:29
     */
    @RabbitListener(queues = Constants.CUSTOMER_START_CHAT)
    public void updateCustomer(WxCpXmlOutMessageDTO dto) {
        String str = IdUtils.get32UUID();
        log.info("消费MQ:[customer_start_chat],事件描述:[成员首次收消息事件],编号:[{}],企业ID:[{}],message[{}]", str, dto.getExtCorpId(), dto);
        RLock lock = customerService.getCustomerSyncLock(dto.getExtCorpId(), dto.getExternalUserId());
        try {
//            if (customerService.trySyncLock(lock)) {
//                refreshCustomer(dto);
//            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("消费MQ异常:[customer_start_chat],事件描述:[成员首次收消息事件],编号:[{}],企业ID:[{}],message[{}],异常原因:[{}],异常描述:[{}]", str, dto.getExtCorpId(), dto, "系统异常", e);
        } finally {
            customerService.releaseSyncLock(lock);
        }
    }


    private void otherAddHandler(WxCpXmlOutMessageDTO dto) {
        log.info("客户新增渠道分析开始...");
        try {
            for (AbstractUpdateCustomerHandler handler : getUpdateCustomerHandlerList()) {
                if (handler.match(dto.getExtCorpId(), dto.getUserId(), dto.getState())) {
                    log.info("客户新增渠道分析匹配到：" + handler);
                    handler.saveHandle(dto);
                }

            }
        } catch (Exception e) {
            log.error("客户新增渠道分析异常，[{}]，异常信息：", JSON.toJSONString(dto), e);
        }

    }

    private void refreshCustomer(WxCpXmlOutMessageDTO dto) throws WxErrorException {
        refreshCustomer(dto, false);
    }


    /**
     * 刷新客户信息
     *
     * @param dto    请求参数
     * @param isSave 是否为新增（将是否移除员工状态置为false）
     * @throws WxErrorException
     */
    private void refreshCustomer(WxCpXmlOutMessageDTO dto, boolean isSave) throws WxErrorException {

        // 渠道活码，判断是否是新客户
        checkNewCustomer(dto);

        if (isSave) {
            //如果在离职继承/在职继承中，给该客户新增标签，详情
            //customerService.handlerTransfer(dto.getExtCorpId(),dto.getUserId(),dto.getExternalUserId());
        }
        // 获取主体配置
        SysCorpConfig sysCorpConfig = sysCorpConfigService.getConfig(dto.getExtCorpId());
        // 获取客户信息
        WxCpExternalContactService externalContactService = new WxCpExternalContactServiceImpl(WxCpConfiguration.getCustomerSecretWxCpService(sysCorpConfig));
        WxCpExternalContactInfo contactDetail = externalContactService.getContactDetail(dto.getExternalUserId(), null);
        List<FollowedUser> followedUsers = contactDetail.getFollowedUsers();
        buildWxCpExternalContactInfo(externalContactService, contactDetail.getNextCursor(), followedUsers, dto.getExternalUserId());

        //刷新客户信息
        followedUsers.forEach(followedUser -> {
            WxCpExternalContactBatchInfo.ExternalContactInfo externalContactInfo = new WxCpExternalContactBatchInfo.ExternalContactInfo();
            externalContactInfo.setExternalContact(contactDetail.getExternalContact());
            externalContactInfo.setFollowInfo(followedUser);
            if ((followedUser.getTagIds() == null || followedUser.getTagIds().length < 1) && followedUser.getTags() != null && followedUser.getTags().length > 0) {
                followedUser.setTagIds(Arrays.stream(followedUser.getTags()).filter(f -> f.getType() == 1).map(FollowedUser.Tag::getTagId).toArray(String[]::new));
            }
            ScrmCustomerInfo customer = customerService.refreshCustomer(externalContactInfo, dto);

            ScrmCustomerStaff customerStaff = customerStaffService.checkExists(dto.getExtCorpId(), followedUser.getUserId(), dto.getExternalUserId());

            if (isSave) {
                if (customer != null) {
                    customer.setHasDelete(0);
                    customerService.updateById(customer);
                }

                //设置当前跟进信息未被客户删除
                if (customerStaff != null && dto.getUserId().equals(customerStaff.getExtStaffId())) {
                    customerStaffService.updateById(customerStaff.setIsDeletedStaff(false));
                }
            }

        });

    }

    private void checkNewCustomer(WxCpXmlOutMessageDTO dto) {

        //变更信息的外部联系人的userid，注意不是企业成员的帐号.
        dto.setIsNewCustomer(!customerService.countByCustomerId(dto.getExtCorpId(), dto.getExternalUserId()));

    }


    private void buildWxCpExternalContactInfo(WxCpExternalContactService externalContactService, String nextCursor, List<FollowedUser> followedUsers, String userId) throws WxErrorException {
        if (StringUtils.isNotBlank(nextCursor)) {
            // 获取企微客户详情
            WxCpExternalContactInfo contactDetail = externalContactService.getContactDetail(userId, nextCursor);
            followedUsers.addAll(contactDetail.getFollowedUsers());
            buildWxCpExternalContactInfo(externalContactService, nextCursor, followedUsers, userId);
        }

    }

    private List<AbstractUpdateCustomerHandler> getUpdateCustomerHandlerList() {

        if (updateCustomerHandlerList == null) {
            Map<String, AbstractUpdateCustomerHandler> handlerMap = SpringUtils.getBeanMap(AbstractUpdateCustomerHandler.class);
            updateCustomerHandlerList = new ArrayList<>(handlerMap.values());

            updateCustomerHandlerList.sort(Comparator.comparingInt(AbstractUpdateCustomerHandler::getSort));
        }

        return updateCustomerHandlerList;
    }

}
